﻿using System;
using System.Linq;
using Prism.Events;
using System.Threading;
using FrameWork.Core.Enum;
using FrameWork.Core.China;
using FrameWork.Core.Event;
using System.Threading.Tasks;
using FrameWork.Core.ThreadPool;
using System.Collections.Generic;
using FrameWork.Core.Chain.Entitys;
using FrameWork.Core.Infrastructure;

namespace FrameWork.Core.Chain.Invengo
{
    public abstract class InvengoChainEngine<P> : IChainEngine<P> where P : ProcessBase
    {
        #region ___类内变量___
        protected static List<P> m_ProcessCollection = new List<P>();
        /// <summary>
        /// 默认任务组(不要修改该值)
        /// </summary>
        protected readonly static int TaskId = 2000;
        protected static object m_lock = new object();
        #endregion

        #region ___构造方法___
        /// <summary>
        /// 构造方法
        /// </summary>
        public InvengoChainEngine()
        {
            EngineContext.Current.Resolve<IEventAggregator>().GetEvent<StopChainEvent>().Subscribe(t =>
            {
                lock (m_lock)
                {
                    var stopedChannels = t == null ? ProcessCollection : ProcessCollection.Where(k => k.Guid.Equals(t.Guid));
                    stopedChannels.ToList().ForEach(k =>
                    {
                        if (k.Cts != null)
                            k.Cts.Cancel();
                        k.AutoReset.Set();
                        k.State = EnumProcessState.Break;
                        k.Exit = t.Exit;
                    });
                    TaskGroupPool.Instance.Clear(TaskId);
                    //ProcessCollection = ProcessCollection.Except(stopedChannels).ToList();
                }
            });
        }
        #endregion

        #region ___类内属性___
        /// <summary>
        /// 流程集合
        /// </summary>
        public static List<P> ProcessCollection
        {
            get { return m_ProcessCollection; }
            set { m_ProcessCollection = value; }
        }
        #endregion

        #region ___基类方法___
        /// <summary>
        /// 获取锁
        /// </summary>
        /// <param name="record"></param>
        /// <returns></returns>
        protected CancellationTokenSource GetCTS(P processBase)
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            cts.Token.Register(() =>
            {
                Console.WriteLine("收到流程【" + processBase.FlowName + "】取消信号，任务待取消");
            });
            return cts;
        }
        #endregion

        #region ___抽象/虚方法___
        /// <summary>
        /// 当前引擎立即执行执行
        /// </summary>
        /// <param name="processBase"></param>
        public virtual void Run(P processBase)
        {
            TaskGroupPool.Instance.Enqueue(() =>
            {
                this.Process(processBase);
            });
        }
        /// <summary>
        /// 独占线程池，同步执行
        /// </summary>
        /// <param name="processBase"></param>
        public virtual void RunWithMonopoly(P processBase)
        {
            processBase.Cts = GetCTS(processBase);
            TaskGroupPool.Instance.Monopoly(() =>
            {
                this.Process(processBase);
            }, processBase.Cts, TaskId);
        }
        /// <summary>
        /// 独占线程池，排队执行
        /// </summary>
        /// <param name="processBase"></param>
        public virtual void RunWithQueue(P processBase)
        {
            processBase.Cts = GetCTS(processBase);
            TaskGroupPool.Instance.Enqueue(() =>
            {
                this.Process(processBase);
            }, processBase.Cts, TaskId);
        }
        /// <summary>
        /// 异步执行
        /// </summary>
        /// <param name="processBase"></param>
        public virtual void RunWithAsync(P processBase)
        {
            ///////////////////////开始流程//////////////////////////////////
            processBase.Cts = GetCTS(processBase);
            Task.Factory.StartNew(() => this.Process(processBase), processBase.Cts.Token);
        }
        /// <summary>
        /// 抽象方法
        /// </summary>
        /// <param name="processBase"></param>
        public abstract void Process(P processBase);
        /// <summary>
        /// 释放信号
        /// </summary>
        /// <param name="record"></param>
        /// <param name="autoResetKey"></param>
        public virtual void Set(P processBase)
        {
            lock (m_lock)
            {
                if (ProcessCollection.Where(n => n.Guid.Equals(processBase.Guid)).Any())
                {
                    var autoResetevent = ProcessCollection.Where(n => n.Guid.Equals(processBase.Guid)).FirstOrDefault();
                    var temp = autoResetevent.AutoReset;
                    temp.Set();
                }
            }
        }
        /// <summary>
        /// 判断流程是否执行中
        /// </summary>
        /// <param name="processBase"></param>
        protected virtual bool HasRegister(P processBase)
        {
            lock (m_lock)
            {
                if (ProcessCollection.Where(n => n.Guid.Equals(processBase.Guid)).Any())
                    return true;
                else
                    ProcessCollection.Add(processBase);
                return false;
            }
        }
        /// <summary>
        /// 流程执行完成后,清理环境
        /// </summary>
        /// <param name="processBase"></param>
        protected virtual void UnRegister(P processBase)
        {
            lock (m_lock)
            {
                var removeProcess = ProcessCollection.Where(n => n.Guid.Equals(processBase.Guid)).FirstOrDefault();
                if (null != removeProcess)
                {
                    ProcessCollection.Remove(removeProcess);
                    EngineContext.Current.Resolve<IEventAggregator>().GetEvent<JumpCahinEvent>().Unsubscribe(removeProcess.JumpToken);
                }
            }
        }
        #endregion
    }
}
